/* ----------------------------------------------------------------------------
* File: api_event_dispatcher_impl.cpp
*
* Desc: Dispatcher for Skype API events - implementation
*
* Created: 30/07/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#include "exception.h"
#include "api_event_dispatcher_impl.h"

#define WAIT_TIME_EVENT_DISPATCHER		0
#define WAIT_TIME_ATTACH				200

namespace SkypeProtection
{
	APIEventDispatcherImpl::APIEventDispatcherImpl(const APIEventDispatcherParams& params)
		throw (Common::Exception)
		: APIProxy(params.registerAPI)
		, m_dispatch_events(params.dispatch_events)
	{
		m_EventHandler.reset(params.APIHandler);
		m_AttachHandler.reset(params.AttachHandler);
	}

	APIEventDispatcherImpl::~APIEventDispatcherImpl()
	{
		Stop();
	}

	Common::Error APIEventDispatcherImpl::RunLogic(SKYPE4COMLib::ISkype* skype)
	{
		std::auto_ptr<EventSink> eventSink;
		if (m_dispatch_events)
			eventSink.reset(new EventSink(m_EventHandler.get()));

		if (StartProxyProcess(skype, eventSink.get()) != Common::SKYPE_SUCCESS)
			return Common::SKYPE_ERROR;

		MSG msg;
		while(!QueryExitStatus(WAIT_TIME_EVENT_DISPATCHER) && GetMessage(&msg, NULL, 0, 0 ))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		StopProxyProcess(skype, eventSink.get());
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIEventDispatcherImpl::StartProxyProcess(SKYPE4COMLib::ISkype* skype, EventSink* eventSink)
	{
		m_Logger->Print("SkypeEventDispatcher::StartProxyProcess() - start");

		// Advise event listener
		if (m_dispatch_events)
		{
			HRESULT hr = eventSink->DispEventAdvise(skype);
			if (hr != S_OK)
			{
				m_Logger->Print("SkypeEventDispatcher: ERROR - Unable to advise event listener");
				throw Common::Exception("SkypeEventDispatcher: ERROR - Unable to advise event listener");
			}
			m_Logger->Print("SkypeEventDispatcher: advised event listener (OK)");
		}

		// Start client
		if (skype->GetClient()->IsRunning == VARIANT_FALSE)
			skype->GetClient()->Start(VARIANT_TRUE, VARIANT_FALSE);

		// Connect to Skype API without waiting
		skype->Attach(6, VARIANT_FALSE);

		// Wait API permission
		SKYPE4COMLib::TAttachmentStatus attachStatus = skype->GetAttachmentStatus();
		while (attachStatus != SKYPE4COMLib::TAttachmentStatus::apiAttachSuccess)
		{
			if (attachStatus == SKYPE4COMLib::TAttachmentStatus::apiAttachRefused)
			{
				if (m_dispatch_events)
					eventSink->DispEventUnadvise(skype);
				m_Logger->Print("SkypeProxy: attach refused (FAILED)");
				throw Common::Exception("Object was refused");
			}
			else
			{
				// notify about attaching process
				if (m_AttachHandler.get())
					m_AttachHandler->OnAttaching();
			}

			Sleep(WAIT_TIME_ATTACH);
			attachStatus = skype->GetAttachmentStatus();
		}

		m_Logger->Print("SkypeProxy: attached (OK)");
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIEventDispatcherImpl::StopProxyProcess(SKYPE4COMLib::ISkype* skype, EventSink* eventSink)
	{
		if (m_dispatch_events)
			eventSink->DispEventUnadvise(skype);
		return Common::SKYPE_SUCCESS;
	}

	std::auto_ptr<APIEventDispatcher> CreateAPIEventDispatcher(const APIEventDispatcherParams& params)
	{
		std::auto_ptr<APIEventDispatcher> dispatcher;
		try
		{
			std::auto_ptr<APIEventDispatcherImpl> obj(new APIEventDispatcherImpl(params));
			
			// Start dispatcher
			if (obj->Start() != Common::SKYPE_SUCCESS)
				return dispatcher;

			dispatcher = obj;
		}
		catch (...)
		{
		}
		return dispatcher;
	}
}